package com.naiterui.ehp.bs.im.network.transfer;

import cn.hutool.core.collection.CollectionUtil;
import com.naiterui.ehp.bp.support.security.HeaderConstant;
import com.naiterui.ehp.bs.im.config.MediaFileConfig;
import com.naiterui.ehp.bs.im.exception.NaiteruiIMException;
import com.naiterui.ehp.bs.im.network.mqtt.MqttClientUtils;
import com.naiterui.ehp.bs.im.network.protocl.Media;
import com.naiterui.ehp.bs.im.network.protocl.Message;
import com.naiterui.ehp.bs.im.network.protocl.OfflineMessage;
import com.naiterui.ehp.bs.im.network.transcode.IMessageTransCoder;
import com.naiterui.ehp.bs.im.remote.IRemoter;
import com.naiterui.ehp.bs.im.repository.mongo.MessageDao;
import com.naiterui.ehp.bs.im.service.message.handler.ReplayHandler;
import com.naiterui.ehp.bs.im.service.message.push.DisturbHandler;
import com.naiterui.ehp.bs.im.utils.Constants;
import com.naiterui.ehp.bs.im.utils.NameUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

/**
 * 负责患者端的消息发送
 */
@Service
public class PatientTransfer implements Transfer {

    /**
     * LOGGER
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(PatientTransfer.class);

    /**
     * 远程依赖服务调用
     */
    private final IRemoter remoter;

    /**
     * 多媒体文件配置
     */
    private final MediaFileConfig config;

    /**
     * 消息编/解码对象
     */
    private final IMessageTransCoder messageTransCoder;

    /**
     * 自动回复
     */
    private final ReplayHandler replayHandler;

    /**
     * 勿扰模式
     */
    private final DisturbHandler disturbHandler;

    /**
     * messageDao：<code>messageDao</code>
     */
    private final MessageDao messageDao;

    public PatientTransfer(IRemoter remoter, MediaFileConfig config, IMessageTransCoder messageTransCoder, ReplayHandler replayHandler,
                           DisturbHandler disturbHandler, MessageDao messageDao) {
        this.remoter = remoter;
        this.config = config;
        this.messageTransCoder = messageTransCoder;
        this.replayHandler = replayHandler;
        this.disturbHandler = disturbHandler;
        this.messageDao = messageDao;
    }

    /**
     * 向医生客户端推送消息
     */
    @Override
    public void sendMessage(final Message<?> message, boolean isOnline) throws NaiteruiIMException {

        // 增加多媒体消息下载地址的域名
        this.addMediaMsgDwnUrl(message);

        // 消息编码
        final String messageStr = this.messageTransCoder.encodeMessage(message);

        // 如果在线直接推送至MQTT
        if (isOnline) {
            MqttClientUtils.publishMessageToClient(NameUtils.drMsgTopic(message.getTo().getId()), messageStr);
        }

        if (this.disturbHandler.isDisturb(message.getTo().getId()) && this.replayHandler.isReplay(message.getTo().getId())) {
            String msg = this.replayHandler.findCurrReplay(message.getTo().getId());
            if (message.getLastPlatform() == null || HeaderConstant.HEADER_ORIGIN_PATIENT_WX == message.getLastPlatform()) {
                // 患者微信端：医生自动回复推送微信
                this.remoter.sendMsgToWx(Constants.MESSAGE_TYPE_TEXT, message.getTo().getId(), message.getFrom().getId(), msg, message.getSession());
                LOGGER.info("send replay to Patient WX, from {} to {} content is {}", message.getTo().getId(), message.getFrom().getId(), msg);
            } else if (this.disturbHandler.isDisturb(message.getTo().getId()) && this.replayHandler.isReplay(message.getTo().getId())) {
                LOGGER.info("send replay to Patient APP, from {} to {} content is {}", message.getTo().getId(), message.getFrom().getId(), msg);
                // 患者APP端：医生自动回复推送app
                Message<String> replayMessage = new Message<String>();
                replayMessage.setContent(msg);
                replayMessage.setFrom(message.getTo());
                replayMessage.setTo(message.getFrom());
                replayMessage.setLastPlatform(message.getLastPlatform());
                replayMessage.setRelation(Constants.MESSAGE_RESOURCE_DOCTOR);
                replayMessage.setSendTime(System.currentTimeMillis());
                replayMessage.setSession(message.getSession());
                replayMessage.setType(Constants.MESSAGE_TYPE_TEXT);
                MqttClientUtils.publishMessageToClient(
                        NameUtils.ptMsgTopic(message.getFrom().getId()), this.messageTransCoder.encodeMessage(replayMessage));

            }
        }

    }

    /**
     * 增加多媒体消息下载地址的域名
     */
    public void addMediaMsgDwnUrl(Message<?> message) {

        // 处理多媒体消息，患者端向医生发送的消息，需要完整的资源下载地址，因此需要拼接上域名
        int type = message.getType();
        if (type == Constants.MESSAGE_TYPE_MEDIA_IMG || type == Constants.MESSAGE_TYPE_MEDIA_AUDIO || type == Constants.MESSAGE_TYPE_MEDIA_VIDEO) {
            // 转换为多媒体消息内容对象
            Media media = (Media) message.getContent();
            media.setPath(this.config.getServerDomain() + media.getPath());
        }
    }

    /**
     * PatientTransfer.handleOfflineMessage()
     */
    @Override
    public void handleOfflineMessage(Long userId) {

        // 获取正常离线消息
        List<Message> commonMessages = this.messageDao.getAndRemoveOfflineMessages(Constants.MESSAGE_RESOURCE_DOCTOR, userId);
        LOGGER.debug("send offline messages commonMessages INFO;target={},commonMessages size={}", userId,
                     null == commonMessages ? 0 : commonMessages.size());
        // 微信跨平台同步数据(来源患者微信端口，多平台同步)
        List<Message> syncMessages = this.messageDao.getAndRemoveSyncOfflineMessages(Constants.MESSAGE_RESOURCE_PATIENT, userId);
        LOGGER.debug("send offline messages commonMessages INFO;target={},syncMessages size={}", userId,
                     null == syncMessages ? 0 : syncMessages.size());

        // 没有离线消息需要发送
        if (CollectionUtil.isEmpty(commonMessages) && CollectionUtil.isEmpty(syncMessages)) {
            return;
        }

        LOGGER.info("send offline messages to pt_{}, commonMessages size is {},syncMessages size is {}", userId,
                    null == commonMessages ? 0 : commonMessages.size(), null == syncMessages ? 0 : syncMessages.size());

        Set<OfflineMessage> targetMessage = new TreeSet<OfflineMessage>();
        for (Message tempCommonMessage : commonMessages) {
            try {
                OfflineMessage tempOfflineMessage = new OfflineMessage(tempCommonMessage);
                targetMessage.add(tempOfflineMessage);
            } catch (Exception e) {
                LOGGER.error(" offline message transfer ERROR , sourceMessage {} ", tempCommonMessage, e);
            }
        }

        if (null != syncMessages && !syncMessages.isEmpty()) {
            for (Message tempSyncMessage : syncMessages) {
                try {
                    OfflineMessage tempOfflineMessage = new OfflineMessage(tempSyncMessage);
                    targetMessage.add(tempOfflineMessage);
                } catch (Exception e) {
                    LOGGER.error(" offline message transfer ERROR , sourceMessage {} ", tempSyncMessage, e, e);
                }
            }
        }

        // 迭代离线消息列表进行消息发送
        for (Iterator<OfflineMessage> iter = targetMessage.iterator(); iter.hasNext(); ) {

            OfflineMessage message = iter.next();
            try {
                if (null == message.getRelation()) {
                    LOGGER.error("send offline message error , empty relation : message {}", message);
                    continue;
                } else if (Constants.MESSAGE_RESOURCE_PATIENT == message.getRelation()) {
                    // 多平台消息同步
                    this.sendSyncOfflineMessage(message);
                } else if (Constants.MESSAGE_RESOURCE_DOCTOR == message.getRelation()) {
                    // 普通离线消息
                    this.sendOfflineMessage(message);
                }
            } catch (NaiteruiIMException e) {
                LOGGER.error("send offline messages to pt_{} failure, exception is {}", userId, e.getMessage(), e);
            }
        }
    }

    /**
     * @param message
     */
    @Override
    public void sendOfflineMessage(Message<?> message) throws NaiteruiIMException {

        // 增加多媒体消息下载地址的域名
        this.addMediaMsgDwnUrl(message);

        String messageStr = null;
        if (null == message.getFrom()) {
            // 公告通知类离线缓存
            messageStr = (String) message.getContent();
        } else {
            // 聊天消息类离线缓存
            messageStr = this.messageTransCoder.encodeMessage(message);
        }

        // 如果在线直接推送至MQTT
        MqttClientUtils.publishMessageToClient(NameUtils.ptMsgTopic(message.getTo().getId()), messageStr);
    }

    /**
     * PatientTransfer.sendSyncOfflineMessage()
     */
    public void sendSyncOfflineMessage(Message<?> message) throws NaiteruiIMException {

        // 增加多媒体消息下载地址的域名
        this.addMediaMsgDwnUrl(message);

        String messageStr = null;
        // 聊天消息类离线缓存
        messageStr = this.messageTransCoder.encodeMessage(message);

        // 推送MQTT
        MqttClientUtils.publishMessageToClient(NameUtils.ptMsgTopic(message.getFrom().getId()), messageStr);
    }

}
